package com.gitee.wsl.android.ext.store

import android.annotation.SuppressLint
import android.app.RecoverableSecurityException
import android.content.ClipData
import android.content.ContentResolver.SCHEME_ANDROID_RESOURCE
import android.content.ContentResolver.SCHEME_CONTENT
import android.content.ContentResolver.SCHEME_FILE
import android.content.ContentUris
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.os.Build
import android.os.CancellationSignal
import android.os.ParcelFileDescriptor
import android.provider.BaseColumns
import android.provider.ContactsContract
import android.provider.MediaStore
import android.provider.OpenableColumns
import android.util.Size
import android.webkit.MimeTypeMap
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.IntentSenderRequest
import androidx.annotation.RequiresApi
import androidx.core.content.FileProvider
import androidx.datastore.preferences.protobuf.ExperimentalApi
import androidx.documentfile.provider.DocumentFile
import com.gitee.wsl.android.ext.ApplicationInit.application
import com.gitee.wsl.android.ext.store.PathExt.EXTERNAL_STORAGE_AUTHORITY
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.InputStream
import java.io.OutputStream


var fileProviderAuthority: String="file"

fun Context.rawIdToUri(
    rawId: Int,
    packageName: String = this.packageName
): Uri {
    return Uri.parse("$SCHEME_ANDROID_RESOURCE://$packageName/$rawId")
}

fun File.getAppUri(authority: String = fileProviderAuthority): Uri =
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        FileProvider.getUriForFile(application, authority, this)
    } else {
        Uri.fromFile(this)
    }

fun Uri.update(vararg pairs: Pair<String, Any?>): Boolean =
    contentResolver.update(
        this, *pairs, where = "${BaseColumns._ID} = ?",
        selectionArgs = arrayOf(ContentUris.parseId(this).toString())
    ) > 0

@SuppressLint("Range")
@ExperimentalApi
fun Uri.delete(launcher: ActivityResultLauncher<IntentSenderRequest>): Boolean =
    @Suppress("DEPRECATION")
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
        val projection = arrayOf(MediaStore.MediaColumns.DATA)
        contentResolver.queryFirst(this, projection) { cursor ->
            File(cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA))).delete()
        } ?: false
    } else {
        try {
            val id: Long = ContentUris.parseId(this)
            contentResolver.delete(this, "${BaseColumns._ID} = ?", arrayOf(id.toString())) > 0
        } catch (securityException: SecurityException) {
            val recoverableSecurityException = securityException as? RecoverableSecurityException
                ?: throw RuntimeException(securityException.message, securityException)
            val intentSender =
                recoverableSecurityException.userAction.actionIntent.intentSender
            launcher.launch(IntentSenderRequest.Builder(intentSender).build())
            false
        }
    }

inline fun <R> Uri.openFileDescriptor(mode: String = "r", crossinline block: (ParcelFileDescriptor) -> R): R? =
    contentResolver.openFileDescriptor(this, mode)?.use(block)

inline fun <R> Uri.openInputStream(crossinline block: (InputStream) -> R): R? {
    val inputStream=if(isFileUri)
        FileInputStream(File(path?:return null))
    else
         contentResolver.openInputStream(this)
    return inputStream?.use(block)
}


inline fun <R> Uri.openOutputStream(append: Boolean = true,crossinline block: (OutputStream) -> R): R? {
    val outputStream=if(isFileUri)
        FileOutputStream(File(path?:return null),append)
    else
        contentResolver.openOutputStream(this)
    return outputStream?.use(block)
}


@RequiresApi(Build.VERSION_CODES.Q)
fun Uri.loadThumbnail(width: Int, height: Int, signal: CancellationSignal? = null): Bitmap =
    contentResolver.loadThumbnail(this, Size(width, height), signal)

inline val Uri.fileExtension: String?
    get() = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType)

inline val Uri.mimeType: String?
    get() = contentResolver.getType(this)

val Uri.size: Long
    @SuppressLint("Range", "Recycle")
    get() = try {
        contentResolver.openFileDescriptor(this, "r")?.statSize
    } catch (e: FileNotFoundException) {
        contentResolver.queryFirst(this, arrayOf(OpenableColumns.SIZE)) { cursor ->
            cursor.getLong(cursor.getColumnIndex(OpenableColumns.SIZE))
        }
    } ?: 0

val Uri.firstPathSegment: String?
    get() = pathSegments.firstOrNull()

val Uri.fileUriIsExists:Boolean
    get() {
        try {
            contentResolver.openFileDescriptor(
                this, "r"
            )?.use {
                return it.fileDescriptor.valid()
            }
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
        }
       return false
    }

val Uri.isAssetUri: Boolean get() = scheme == SCHEME_FILE && firstPathSegment == "android_asset"

val Uri.isContentUri: Boolean get() = scheme == SCHEME_CONTENT
val Uri.isContactPhotoUri: Boolean get() = authority == ContactsContract.AUTHORITY && lastPathSegment == ContactsContract.Contacts.Photo.DISPLAY_PHOTO

val Uri.isMediaFile: Boolean
    get() = authority == MediaStore.AUTHORITY
val Uri.isMusicThumbnailUri: Boolean get() {
    if (!isMediaFile) return false
    val segments = pathSegments
    val size = segments.size
    return size >= 3 && segments[size - 3] == "audio" && segments[size - 2] == "albums"
}
val Uri.isHttpUri: Boolean get() = scheme == "http" || scheme == "https"

val Uri.isFileUri: Boolean get() = scheme == SCHEME_FILE

val Uri.isResourceUri: Boolean get() = scheme == SCHEME_ANDROID_RESOURCE

val Uri.isLocalUri:Boolean get() = isFileUri or isResourceUri or isContentUri

val Uri.isExternalStorageDocument: Boolean
    get() = authority == EXTERNAL_STORAGE_AUTHORITY

/**
 * For URI [DOCUMENTS_TREE_URI]
 */
val Uri.isDocumentsDocument: Boolean
    get() = isExternalStorageDocument && path?.let { it.startsWith("/tree/home:") || it.startsWith("/document/home:") } == true


val Uri.isTreeDocumentFile: Boolean
    get() = path?.startsWith("/tree/") == true

fun Uri.toTreeDocumentFile():DocumentFile?{
   return try {
        DocumentFile.fromTreeUri(application, this)
    } catch (e: Exception) {
        null
    }
}

fun Uri.toSingleDocumentFile():DocumentFile?{
    return try {
        DocumentFile.fromSingleUri(application, this)
    } catch (e: Exception) {
        null
    }
}

fun Intent?.getUri():Uri?{
    var uri: Uri? = null
    val intent=this
    if (intent != null) {
        val action: String? = intent.action
        if (Intent.ACTION_VIEW == action) {
            // 获取 VIEW Intent 中的 URI
            uri = intent.data
        } else if (Intent.ACTION_SEND == action) {
            // 获取 SEND Intent 中的 URI
            uri = intent.getParcelableExtra(Intent.EXTRA_STREAM)
        } else if (Intent.ACTION_SEND_MULTIPLE == action) {
            // 获取 SEND_MULTIPLE Intent 中的 URI
            val uris: ArrayList<Uri>? = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM)
            if (!uris.isNullOrEmpty()) {
                uri = uris[0]
            }
        } else if (Intent.ACTION_CHOOSER == action) {
            // 获取 CHOOSER Intent 中的 URI
            val chooserIntent = Intent.createChooser(intent, "Select")
            if (chooserIntent != null) {
                uri = chooserIntent.getParcelableExtra(Intent.EXTRA_STREAM)
            }
        } else {
            // 其他情况，根据数据类型获取 URI
            uri = intent.data
            if (uri == null) {
                val type: String? = intent.type
                if (type != null) {
                    // 根据数据类型获取 URI
                    val types = type.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                    if (types.size == 2) {
                        val dataType = types[0]
                        val dataString: String? = intent.getStringExtra(Intent.EXTRA_TEXT)
                        if (dataString != null) {
                            uri = Uri.parse(dataString)
                        }
                    }
                }
            }
        }
    }
    return uri
}

fun Intent?.getUriCount():Int{
    var uriCount = 0
    val intent=this
    if (intent != null) {
        val clipData: ClipData? = intent.clipData
        if (clipData != null) {
            uriCount = clipData.itemCount
        } else {
            val uri: Uri? = intent.data
            if (uri != null) {
                uriCount = 1
            }
        }
    }
    return uriCount
}